package com.yuneec.fly.fragments;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.yuneec.fly.R;
import com.yuneec.fly.events.EventBusFactory;
import com.yuneec.fly.events.uiEvent.ShowNoticeMessageEvent;
import com.yuneec.fly.events.uiEvent.ShowWarningEvent;

import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

/**
 * Created by jw.gu on 2016/6/29.
 */
public class MessageFragment extends BaseFragment {
    private static final int SHOW_NOTICE = 0;
    private static final int SHOW_WARNING = 1;
    private static final int HIDE_WARNING = 2;
    private static final int ADD_WARNING = 3;
    private LinearLayout warningsContainer;
    private LinearLayout noticesContainer;
    private Queue<String> notices;
    private Queue<String> warnings;
    private ArrayList<String> showingWarnings;
    private AlphaAnimation warningsAnimation;
    private HashMap<String, View> warningViews;
    private List<View> noticesViews;

    private Handler messageHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            String message;
            switch (msg.what) {
                case SHOW_NOTICE:
                    showNotice();
                    break;
                case ADD_WARNING:
                    message = (String) msg.obj;
                    if (!showingWarnings.contains(message)) {
                        warnings.offer(message);
                        showingWarning();
                        messageHandler.sendEmptyMessage(SHOW_WARNING);
                    }
                    break;
                case SHOW_WARNING:
                    showingWarning();
                    break;
                case HIDE_WARNING:
                    message = (String) msg.obj;
                    if (warningViews.containsKey(message)) {
                        warningViews.get(message).clearAnimation();
                        warningsContainer.removeView(warningViews.get(message));
                        warningViews.remove(message);
                    }
                    if (showingWarnings.contains(message)) {
                        showingWarnings.remove(message);
                    }
                    break;
            }
        }
    };

    @Override
    protected int getContentViewResourceId() {
        return R.layout.fragment_message;
    }

    @Override
    public void init(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        warningViews = new HashMap<>();
        noticesViews = Collections.synchronizedList(new ArrayList<View>());
        warningsContainer = (LinearLayout) selfView.findViewById(R.id.warningsContainer);
        noticesContainer = (LinearLayout) selfView.findViewById(R.id.noticesContainer);
        notices = new ConcurrentLinkedQueue<>();
        warnings = new ConcurrentLinkedQueue<>();
        showingWarnings = new ArrayList<>();
        initAnimation();
        selfView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
    }

    private void initAnimation() {
        warningsAnimation = new AlphaAnimation(1f, 0.5f);
        warningsAnimation.setRepeatMode(Animation.REVERSE);
        warningsAnimation.setDuration(800);
        warningsAnimation.setRepeatCount(Integer.MAX_VALUE);
    }

    @Override
    public void onStart() {
        super.onStart();
        EventBusFactory.getUiBus().register(this);
    }

    @Override
    public void onStop() {
        super.onStop();
        notices.clear();
        EventBusFactory.getUiBus().unregister(this);
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onShowMessage(ShowNoticeMessageEvent event) {
        notices.offer(event.message);
        messageHandler.sendEmptyMessage(SHOW_NOTICE);
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onShowMessage(ShowWarningEvent event) {
        if (event.show) {
            messageHandler.obtainMessage(ADD_WARNING, event.message).sendToTarget();
        } else {
            messageHandler.obtainMessage(HIDE_WARNING, event.message).sendToTarget();
        }
    }

    private synchronized void showNotice() {
        String notice = notices.poll();
        if (notice == null) {
            return;
        }
        while (noticesViews.size() >= 3) {
            View view = noticesViews.get(0);
            ((AnimatorSet) (view).getTag()).cancel();
            noticesViews.remove(view);
            noticesContainer.removeView(view);
        }
        View view = LayoutInflater.from(getActivity()).inflate(R.layout.item_notice_text, null);
        ((TextView) view.findViewById(R.id.messageTV)).setText(notice);
        noticesContainer.addView(view);
        AnimatorSet noticeAnimatorSet = getNoticeAnimatorSet(view);
        view.setTag(noticeAnimatorSet);
        noticeAnimatorSet.start();
        noticesViews.add(view);
    }

    private AnimatorSet getNoticeAnimatorSet(final View view) {
        AnimatorSet animatorSet = new AnimatorSet();
        ObjectAnimator trans = ObjectAnimator.ofFloat(view, "X", 450, 0);
        trans.setDuration(1000);
        ObjectAnimator delay = ObjectAnimator.ofFloat(view, "alpha", 1f, 1f);
        delay.setDuration(4000);
        ObjectAnimator alpha = ObjectAnimator.ofFloat(view, "alpha", 1f, 0.1f);
        alpha.setDuration(1000);
        animatorSet.playSequentially(trans, delay, alpha);
        animatorSet.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                noticesViews.remove(view);
                noticesContainer.removeView(view);
            }
        });
        return animatorSet;
    }

    private synchronized void showingWarning() {
        String warning = warnings.poll();
        if (warning == null) {
            return;
        }
        if (!warningViews.containsKey(warning)) {
            View view = LayoutInflater.from(getActivity()).inflate(R.layout.item_warnning_text, null);
            ((TextView) view.findViewById(R.id.messageTV)).setText(warning);
            view.startAnimation(warningsAnimation);
            warningsContainer.addView(view, 0);
            warningViews.put(warning, view);
        }
        messageHandler.sendEmptyMessage(SHOW_WARNING);
    }
}
